﻿Public Module ContentClasses


    Private _UnitValues As New Dictionary(Of String, Double) From {
    {"", 1},
    {"cal", 1},
    {"קקל", 1},
    {"קק""ל", 1},
    {"joule", 0.239},
    {"mg", 1},
    {"מ""ג", 1},
    {"מג", 1},
    {"מיליגרם", 1},
    {"ג", 1000},
    {"ג'", 1000},
    {"גרם", 1000},
    {"g", 1000},
    {"ounce", 28349.5},
    {"oz", 28349.5}
}


    Private Function ConvertUnit(Value As Double, SourceUnit As String, TargetUnit As String) As Double
        SourceUnit = SourceUnit.ToLower
        TargetUnit = TargetUnit.ToLower
        Return Value * _UnitValues(SourceUnit) / _UnitValues(TargetUnit)
    End Function

    Public Class NutritionalDataField

        Enum Desiredness As Integer
            good
            neutral
            avoid
            bad
        End Enum

        Public Property Name As String
        Public Property Names As String()
        Public Property Unit As String
        Public Property DailyAmount As Double
        Public Property Ident As Boolean

        Public Property Desired As Desiredness

        Sub New(Name As String, OtherNames As String(), Unit As String, DailyAmount As Double, Desired As Desiredness, Optional Ident As Boolean = False)
            Me.Name = Name
            Me.Names = OtherNames
            Array.Resize(Me.Names, Me.Names.Length + 1)
            Me.Names(Me.Names.Length - 1) = Name

            Me.Unit = Unit
            Me.DailyAmount = DailyAmount
            Me.Ident = Ident
            Me.Desired = Desired
        End Sub
    End Class


    Public Class NutritionalData

        Public Shared Fields As NutritionalDataField() = {
         New NutritionalDataField("קלוריות", {"total calories", "calories", "energy", "אנרגיה"}, "", 2000, NutritionalDataField.Desiredness.avoid),
         New NutritionalDataField("קלוריות משומן", {"fat calories"}, "", 0, NutritionalDataField.Desiredness.neutral, True),
         New NutritionalDataField("שומן", {"fat", "total fat", "שומנים"}, "גרם", 65, NutritionalDataField.Desiredness.avoid),
         New NutritionalDataField("שומן רווי", {"saturated fat"}, "גרם", 20, NutritionalDataField.Desiredness.bad, True),
         New NutritionalDataField("שומן טראנס", {"trans fat", "שומן טרנס"}, "מ""ג", 1500, NutritionalDataField.Desiredness.bad, True),
         New NutritionalDataField("כולסטרול", {"cholesterol"}, "מ""ג", 300, NutritionalDataField.Desiredness.bad),
         New NutritionalDataField("נתרן", {"sodium"}, "מ""ג", 2400, NutritionalDataField.Desiredness.bad),
         New NutritionalDataField("פחמימות", {"carbohydrates", "total carbohydrates", "carbs"}, "גרם", 300, NutritionalDataField.Desiredness.avoid),
         New NutritionalDataField("סיבים", {"fiber", "dietary fiber", "סיבים תזונתיים"}, "גרם", 25, NutritionalDataField.Desiredness.good, True),
         New NutritionalDataField("סוכרים", {"sugar", "sugars", "סוכר"}, "גרם", 40, NutritionalDataField.Desiredness.bad, True),
          New NutritionalDataField("חלבון", {"protein", "חלבונים"}, "גרם", 50, NutritionalDataField.Desiredness.good)
        }

        Public Property NumberOfServings As Integer = 1
        Public Property ServingDescription As String
        Public Property Values As SerializableDictionary(Of String, Double)

        Public ReadOnly Property Valid As Boolean
            Get
                Return Values.Count > 0
            End Get
        End Property

        Public Property NutritionalDataString As String
            Get
                Dim b As New StringBuilder
                For Each f In Fields
                    If Values.ContainsKey(f.Name) Then
                        b.Append(f.Name)
                        b.Append(" ")
                        b.Append(Values(f.Name))
                        b.Append(" ")
                        b.Append(f.Unit)
                        b.AppendLine()
                    End If
                Next
                Return b.ToString()
            End Get
            Set(value As String)

                If value Is Nothing Then
                    Me.Values.Clear()
                    Return
                End If

                Dim regex As New Regex("(?<field>\w[\w ]*\w) +?(?<value>[\d\.,]+) *(?<unit>[\w""']*)")

                Dim matches = regex.Matches(value.ToLower)
                For Each match As Match In matches
                    For Each f In Fields
                        If f.Names.Contains(match.Groups("field").Value) Then
                            Dim convertedValue As Double = ConvertUnit(CDbl(match.Groups("value").Value), match.Groups("unit").Value, f.Unit)
                            Me.Values(f.Name) = convertedValue
                            GoTo next_match
                        End If
                        'Unknown field
                    Next
next_match:
                Next

            End Set
        End Property

        Public Function FieldRowRatingClass(Field As NutritionalDataField) As String
            If Me.Values.ContainsKey(Field.Name) Then
                Return "nutrition-" & Field.Desired.ToString() & "-" & Me.DailyPercentageGroup(Field)
            Else
                Return ""
            End If
        End Function

        Sub New(NutritionalDataString As String, NumberOfServings As Integer, ServingDescription As String)
            Me.NumberOfServings = NumberOfServings
            Me.ServingDescription = ServingDescription
            Me.Values = New SerializableDictionary(Of String, Double)
            Me.NutritionalDataString = NutritionalDataString
        End Sub

        Sub New()
            Me.Values = New SerializableDictionary(Of String, Double)
        End Sub

        Public Function ValuePerServing(Field As NutritionalDataField) As Double
            Return Values(Field.Name) / NumberOfServings
        End Function
        Public Function DailyPercentage(Field As NutritionalDataField) As Double
            If Field.DailyAmount = 0 Then Return ""
            Return ValuePerServing(Field) / Field.DailyAmount
        End Function
        Public Function DailyPercentageGroup(Field As NutritionalDataField) As Integer
            If Field.DailyAmount = 0 Then Return 100
            Return Math.Min((ValuePerServing(Field) / (Field.DailyAmount) * 100 \ 20) * 20, 100)
        End Function

    End Class

End Module
